<html>
    <head>
        <title>自定义指令</title>
    </head>
    <body>
        <script>
            // 自定义指令
                    // 一、 简介
                            /*
                                除了核心功能默认内值的指令 (v-model 和 v-show)，Vue也"允许注册自定义指令"。
                                注意，在Vue 2.0 中，代码复用和抽象的主要形式是组件。
                                然而，有的情况下，你仍然需要对普通DOM元素进行第二层操作， 这时候就会用到"自定义指令"：
                            */
                            // 例如：
                                    // <input type="text" >

                            /*
                                当页面加载时，该元素将获得焦点(注意：autofocus 在移动版 Safari上不工作)。
                                事实上，只要你在打开这个页面后还没点击过任何内容，这个输入框就应该还是处于聚焦状态。
                                现在，让我们用指令来实现这个功能：
                            */
                                
                            // 注册一个全局自定义指令 'v-focus'
                                    Vue.directive('focus',{
                                        // 当被绑定的元素插入到DOM中时....
                                        inserted:function(el){
                                            // 聚焦元素
                                            el.focus()
                                        }
                                    }) 
                                    
                            // 如果想注册局部指令，组件中也接受一个 directives 的选项：
                                    directives:{
                                        focus:{
                                            // 指令的定义
                                            inserted:function(el){
                                                el.focus()
                                            }
                                        }
                                    }
                            // 然后你可以在模板中任何元素上使用新的 v-focus 指令:
                                    /*
                                        <input v-focus>
                                    */

                    // 二、钩子函数
                            /*
                                一个指令定义对象可以提供如下几个钩子函数(均为可选)：
                                    1.bind:      只调用一次，指令第一次绑定到元素时被调用。在这里可以进行一次性的初始化设置。

                                    2.inserted:  被绑定元素插入父节点时调用(仅保证父节点存在，但不一定已经被插入文档中)

                                    3.update:    所在组件的VNode(虚拟节点)更新时调用，"但是可能发生在其子VNode更新之前"。指令的值可能发生了改变，也可能没有。
                                                 但是你可以通过比较更新前后的值来忽略不必要的模板更新(详细的钩子函数参数参见下)
                                                 (我们会在稍后讨论渲染函数时介绍更多VNodes的细节)

                                    4.componentUpdated:  指令在组件的VNode及其子VNode全部更新后调用。

                                    5.unbind:    值调用一次，指令与元素解绑时调用。

                            */


                            //  接下来我们来看一下钩子函数的参数： (即为 el,binding、vnode、oldVnode)

                            
                    // 三、钩子函数参数
                            /*
                                  指令的钩子函数会被传入一下参数：
                                    1.el:        指令所绑定的元素，可以用来直接操作DOM

                                    2.binding:   一个对象，包含以下属性：
                                                 name:       指令名，不包括 v- 前缀。
                                                 value:      指令的绑定值，例如： v-my-directive="1+1" 中，绑定值为2.
                                                 oldValue:   指令绑定的前一个值，仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
                                                 expression: 字符串形式的指令表达式。 例如 v-my-directive="1+1"中，表达式为 "1+1"
                                                 arg:        传给指令的参数，可选。  例如， v-my-directive:foo 中，参数为"foo"
                                                 modifiers:  一个包含修饰符的对象。  例如， v-my-directive.foo.bar 中，修饰符独享为 { foo: true, bar: true }
                                    3.vnode:      Vue编译生成的虚拟节点。(请移步 "VNode Api"来了解更多详情)
                                    4.oldVnode:   上一个虚拟节点，仅在 update 和 componentUpdated 钩子中可用


                                    除了 el 之外，其它参数都应该是只读的，切勿进行修改。
                                    如果需要在钩子之间共享数据，建议通过元素的 dataset 来进行。
                            */

                            // 这是一个实用了这些 property 的自定义钩子样例：
                                    /*
                                        <div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
                                    */

                                        Vue.directive('dome',{
                                            bind:function(el,binding,vnode){
                                                var s= JSON.stringify;  // 这是个简写，表示 s 函数等价于JSON.Stringify
                                                el.innerHTML=
                                                    'name:'+s(binding.name) +'<br>'+ // binding.name 指令名
                                                    'value:'+s(binding.value)+'<br/>'+  // binding.value 指令的绑定值
                                                    'expression:'+s(binding.expreesion)+'<br/>'+ // binding.expression 指令字符串表达式
                                                    'argument:'+s(binding.arg)+'<br/>' + // binding.arg 指令参数
                                                    'modifiers:'+s(binding.modifiers)+'<br/>' + // binding.modifiers 指令修饰符
                                                    'vnode keys:'+ Object.keys(vnode).join(',')
                                            }
                                        })


                                        new Vue({
                                            el:'#hook-arguments-example',
                                            data:{
                                                message:'hello!'
                                            }
                                        });

                                    // DOM中将会显示：
                                        /*
                                            name:"demo"
                                            value:"hello!"
                                            expression:"message"
                                            argument:"foo"
                                            modifiers:{"a":true,"b":true}
                                            vnode keys: tag,data,children,text,elm,ns,context,fnContext,fnOptions,fnScopeId,key,componentOptions,componentInstance,parent,
                                                        raw,isStatic,isRootInsert,isComment,isCloned,isOnce,asyncFactory,asyncMeta,isAsyncPlaceholder
                                        */



                                // ★、动态指令参数
                                        /*
                                            指令的参数可以是动态的。
                                            例如，在 v-mydirective:[argument]="value" 中， argument 参数可以根据组件实例数据进行更新！
                                            这使得自定义指令可以在应用中被灵活使用。

                                            例如，你想要创建一个自定义指令，用来通过固定布局将元素固定在页面上。

                                            我们可以像这样创建一个通过指令值来更新竖直位置像素值得自定义指令：
                                                <div id="baseexample">
                                                    <p>Scroll down the page </p>
                                                    <p v-pin:"200"> Stick me 200px,from the top of the page</p>
                                                </div>
                                        */

                                            Vue.directive('pin',{
                                                bind:function(el,binding,vnode){
                                                    el.style.position ='fixed'
                                                    el.style.top = binding.value +'px'
                                                }
                                            })


                                            new Vue({
                                                el:'#baseexample'
                                            })

                                        /*
                                            这会把该元素固定在距离顶部200像素的位置。
                                            但如果场景是我们需要把元素固定在左侧而不是顶部又该怎么办呢？  
                                            这时，使用动态参数就可以非常方便地根据每个组件实例来进行更新。

                                                例如：
                                                    <div id="dynamicexample">
                                                        <h3>Scroll down inside this section</h3>
                                                        <p v-pin:[direction]="200">I am pinned onto the page to the left</p>
                                                    </div>
                                        */

                                                    Vue.directive('pin',{
                                                        bind:function(el,binding,vnodel){
                                                            el.style.position='fixed'
                                                            var s = (binding.arg=='left'? 'left':'top')
                                                            el.style[s] = binding.value+'px'
                                                        }
                                                    })

                                                    new Vue({
                                                        el:'#dynamicexample',
                                                        data:function(){
                                                            return {
                                                                direction:'left'
                                                            }
                                                        }
                                                    });

                                                // 这样这个自定义指令现在的灵活性就足以支持一些不同的用例了。

                // 函数简写
                          /*
                              在很多时候，你可能想在 bind 和 update 时触发相同行为，而不关心其他的钩子。
                              比如这样：
                          */    
                                                Vue.direction('color-swatch',function(el,binding){
                                                    el.style.backgroundColor= binding.value
                                                })


                // 对象字面量
                          /*
                               如果指令需要多个值，可以传入一个JavaScript对像字面量。记住，指令函数能够接受所有合法JavaScript表达式。

                                    eg:

                                            <div v-demo="{color:'white',text:'hello!'}"></div>
                          */
                                            Vue.direction('demo',function(el,binding){
                                                console.log(binding.value.color); // ===> 'white'
                                                console.log(binding.value.text);  // ===> 'hello!'
                                            })
                                                

                                    
        </script>               
    </body>
</html>